package cn.jiedanba.cacert.ocspserver.service.impl;

import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.List;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.cert.ocsp.OCSPReq;
import org.bouncycastle.cert.ocsp.OCSPResp;
import org.bouncycastle.cert.ocsp.OCSPRespBuilder;
import org.bouncycastle.cert.ocsp.Req;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.jiedanba.cacert.common.ca.PkiUtil;
import cn.jiedanba.cacert.common.ca.cert.enums.CertStatusEnum;
import cn.jiedanba.cacert.common.ca.ocsp.OCSPUtil;
import cn.jiedanba.cacert.common.ca.ocsp.domain.OCSP;
import cn.jiedanba.cacert.common.config.Configs;
import cn.jiedanba.cacert.common.result.ResponseResult;
import cn.jiedanba.cacert.common.util.DateUtil;
import cn.jiedanba.cacert.mapper.CertMapper;
import cn.jiedanba.cacert.mapper.CertRevokeMapper;
import cn.jiedanba.cacert.mapper.RootCaMapper;
import cn.jiedanba.cacert.mapper.RootRevokeMapper;
import cn.jiedanba.cacert.mapper.SysCertMapper;
import cn.jiedanba.cacert.model.Cert;
import cn.jiedanba.cacert.model.CertRevoke;
import cn.jiedanba.cacert.model.RootCa;
import cn.jiedanba.cacert.model.RootRevoke;
import cn.jiedanba.cacert.model.SysCert;
import cn.jiedanba.cacert.ocspserver.service.OcspService;
import cn.jiedanba.cacert.table.Tables;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class OcspServiceImpl implements OcspService {

	@Autowired
	private CertMapper certMapper;

	@Autowired
	private RootCaMapper rootCaMapper;

	@Autowired
	private SysCertMapper sysCertMapper;

	@Autowired
	private CertRevokeMapper certRevokeMapper;

	@Autowired
	private RootRevokeMapper rootRevokeMapper;

	/**
	 * ocsp状态查询
	 * 
	 * @param ocspreqdata
	 * @return
	 */
	@Override
	public ResponseResult ocspQuery(byte[] ocspreqdata) {
		try {
			OCSPReq ocspReq = new OCSPReq(ocspreqdata);
			Req[] requests = ocspReq.getRequestList();
			if (requests == null) {
				return ResponseResult
						.success(new OCSPRespBuilder().build(OCSPResp.MALFORMED_REQUEST, null).getEncoded());
			}
			Date nextUpdate = DateUtil.getNextMinute(new Date(), 720);
			OCSP ocsp = new OCSP();
			ocsp.setOcspReq(ocspReq);
			ocsp.setRequests(requests);
			ocsp.setNextUpdate(nextUpdate);

			SysCert ocspRsaCert = sysCertMapper.selectOneById(Configs.get("ocsp.rsa.cert"));
			if (ocspRsaCert == null) {
				return ResponseResult.fail("未配置OCSP_RSA证书");
			}

			if (ocspRsaCert.getStatus().equals(CertStatusEnum.REVOKE.code)) {
				return ResponseResult.fail("OCSP_RSA证书已被吊销");
			}

			X509Certificate rsaSignCert = PkiUtil.readX509Certificate(Base64.decodeBase64(ocspRsaCert.getSignCert()));
			Boolean isOcspCert = false;
			List<String> usages = rsaSignCert.getExtendedKeyUsage();
			if (usages != null && !usages.isEmpty()) {
				for (String usage : usages) {
					// 是时间戳证书
					if (usage.equals("1.3.6.1.5.5.7.3.9")) {
						isOcspCert = true;
						break;
					}
				}
			} else {
				return ResponseResult.fail("OCSP_RSA证书错误");
			}
			if (!isOcspCert) {
				return ResponseResult.fail("OCSP_RSA证书错误");
			}

			SysCert ocspSM2Cert = sysCertMapper.selectOneById(Configs.get("ocsp.sm2.cert"));
			if (ocspSM2Cert == null) {
				return ResponseResult.fail("未配置OCSP_SM2证书");
			}

			X509Certificate sm2SignCert = PkiUtil.readX509Certificate(Base64.decodeBase64(ocspSM2Cert.getSignCert()));
			Boolean isOcspSM2Cert = false;
			List<String> usages2 = sm2SignCert.getExtendedKeyUsage();
			if (usages2 != null && !usages2.isEmpty()) {
				for (String usage : usages2) {
					// 是时间戳证书
					if (usage.equals("1.3.6.1.5.5.7.3.9")) {
						isOcspSM2Cert = true;
						break;
					}
				}
			} else {
				return ResponseResult.fail("OCSP_SM2证书错误");
			}
			if (!isOcspSM2Cert) {
				return ResponseResult.fail("OCSP_SM2证书错误");
			}

			if (ocspSM2Cert.getStatus().equals(CertStatusEnum.REVOKE.code)) {
				return ResponseResult.fail("OCSP_SM2证书已被吊销");
			}

			String sn = PkiUtil.serialNumberConvertString(requests[0].getCertID().getSerialNumber());

			// 查询用户证书
			Cert cert = certMapper.selectOneByCondition(Tables.CERT.SERIAL_NUMBER.eq(sn));
			if (cert != null) {
				ocsp.setStatus(cert.getStatus());
				if (cert.getSigAlgName().contains("RSA")) {
					ocsp.setOcspSignCert(rsaSignCert);
					ocsp.setOcspPk(PkiUtil.getPrivateKey(Base64.decodeBase64(ocspRsaCert.getPrivateKey())));
				} else if (cert.getSigAlgName().contains("SM2")) {
					ocsp.setOcspSignCert(sm2SignCert);
					ocsp.setOcspPk(PkiUtil.getPrivateKey(Base64.decodeBase64(ocspSM2Cert.getPrivateKey())));
				}

				// 已被吊销
				if (cert.getStatus().equals(CertStatusEnum.REVOKE.code)) {
					CertRevoke certRevoke = certRevokeMapper
							.selectOneByCondition(Tables.CERT_REVOKE.CERT_ID.eq(cert.getId()));
					Date revocationDate = certRevoke.getRevokeDate();
					int revocationReason = certRevoke.getReason();
					ocsp.setRevokeDate(revocationDate);
					ocsp.setRevokeReason(revocationReason);
				}

				return ResponseResult.success(OCSPUtil.sign(ocsp));
			}

			// 查询系统证书
			SysCert sysCert = sysCertMapper.selectOneByCondition(Tables.SYS_CERT.SERIAL_NUMBER.eq(sn));
			if (sysCert != null) {
				ocsp.setStatus(sysCert.getStatus());
				if (sysCert.getSigAlgName().contains("RSA")) {
					ocsp.setOcspSignCert(rsaSignCert);
					ocsp.setOcspPk(PkiUtil.getPrivateKey(Base64.decodeBase64(ocspRsaCert.getPrivateKey())));
				} else if (sysCert.getSigAlgName().contains("SM2")) {
					ocsp.setOcspSignCert(sm2SignCert);
					ocsp.setOcspPk(PkiUtil.getPrivateKey(Base64.decodeBase64(ocspSM2Cert.getPrivateKey())));
				}
				// 已被吊销
				if (sysCert.getStatus().equals(CertStatusEnum.REVOKE.code)) {
					CertRevoke certRevoke = certRevokeMapper
							.selectOneByCondition(Tables.CERT_REVOKE.CERT_ID.eq(sysCert.getId()));
					Date revocationDate = certRevoke.getRevokeDate();
					int revocationReason = certRevoke.getReason();
					ocsp.setRevokeDate(revocationDate);
					ocsp.setRevokeReason(revocationReason);
				}
				return ResponseResult.success(OCSPUtil.sign(ocsp));
			}

			// 查询根证书
			RootCa rootCa = rootCaMapper.selectOneByCondition(Tables.ROOT_CA.SERIAL_NUMBER.eq(sn));
			if (rootCa != null) {
				ocsp.setStatus(rootCa.getStatus());
				if (rootCa.getSignAlgorithm().contains("RSA")) {
					ocsp.setOcspSignCert(rsaSignCert);
					ocsp.setOcspPk(PkiUtil.getPrivateKey(Base64.decodeBase64(ocspRsaCert.getPrivateKey())));
				} else if (rootCa.getSignAlgorithm().contains("SM2")) {
					ocsp.setOcspSignCert(sm2SignCert);
					ocsp.setOcspPk(PkiUtil.getPrivateKey(Base64.decodeBase64(ocspSM2Cert.getPrivateKey())));
				}
				// 已被吊销
				if (rootCa.getStatus().equals(CertStatusEnum.REVOKE.code)) {
					RootRevoke rootRevoke = rootRevokeMapper
							.selectOneByCondition(Tables.ROOT_REVOKE.SERIAL_NUMBER.eq(sn));
					Date revocationDate = rootRevoke.getRevokeDate();
					int revocationReason = rootRevoke.getReason();
					ocsp.setRevokeDate(revocationDate);
					ocsp.setRevokeReason(revocationReason);
				}
				return ResponseResult.success(OCSPUtil.sign(ocsp));
			}
			return ResponseResult.success(new OCSPRespBuilder().build(OCSPResp.MALFORMED_REQUEST, null).getEncoded());
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new RuntimeException("OCSP状态查询异常");
		}

	}

}
